package com.sun.misc;

import java.lang.reflect.Field;

/**
 * 主要提供一些用于执行低级别、不安全操作的方法，如直接访问系统内存资源、自主管理内存资源等，这些方法在提升Java运行效率、增强Java语言底层资源操作能力方面起到了很大的作用。但由于Unsafe类使Java语言拥有了类似C语言指针一样操作内存空间的能力，这无疑也增加了程序发生相关指针问题的风险。
 *
 * https://tech.meituan.com/2019/02/14/talk-about-java-magic-class-unsafe.html
 */
public class UnsafeDemo {

    //分配内存, 相当于C++的malloc函数
    public native long allocateMemory(long bytes);
    //扩充内存
    public native long reallocateMemory(long address, long bytes);
    //释放内存
    public native void freeMemory(long address);
    //在给定的内存块中设置值
    public native void setMemory(Object o, long offset, long bytes, byte value);
    //内存拷贝
    public native void copyMemory(Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes);
    //获取给定地址值，忽略修饰限定符的访问限制。与此类似操作还有: getInt，getDouble，getLong，getChar等
    public native Object getObject(Object o, long offset);
    //为给定地址设置值，忽略修饰限定符的访问限制，与此类似操作还有: putInt,putDouble，putLong，putChar等
    public native void putObject(Object o, long offset, Object x);
    //获取给定地址的byte类型的值（当且仅当该内存地址为allocateMemory分配时，此方法结果为确定的）
    public native byte getByte(long address);
    //为给定地址设置byte类型的值（当且仅当该内存地址为allocateMemory分配时，此方法结果才是确定的）
    public native void putByte(long address, byte x);

    //返回对象成员属性在内存地址相对于此对象的内存地址的偏移量
    public native long objectFieldOffset(Field f);
    //从对象的指定偏移量处获取变量的引用，使用volatile的加载语义
    public native Object getObjectVolatile(Object o, long offset);
    //存储变量的引用到对象的指定的偏移量处，使用volatile的存储语义
    public native void putObjectVolatile(Object o, long offset, Object x);
//    //有序、延迟版本的putObjectVolatile方法，不保证值的改变被其他线程立即看到。只有在field被volatile修饰符修饰时有效
    public native void putOrderedObject(Object o, long offset, Object x);
//    //绕过构造方法、初始化代码来创建对象
    public native Object allocateInstance(Class<?> cls) throws InstantiationException;

    /**
     *  CAS
     * @param o         包含要修改field的对象
     * @param offset    对象中某field的偏移量
     * @param expected  期望值
     * @param update    更新值
     * @return          true | false
     */
    public final native boolean compareAndSwapObject(Object o, long offset,  Object expected, Object update);

    public final native boolean compareAndSwapInt(Object o, long offset, int expected,int update);

    public final native boolean compareAndSwapLong(Object o, long offset, long expected, long update);
}
